package com.rslai.base.tool.servertest.preprocessor;

import com.rslai.base.tool.servertest.dsl.DSLParamParse;
import com.rslai.base.tool.servertest.util.XMLUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.dom4j.Element;

public class DataCaseProcessor {
    private static final String DEFAULT = "default";
    public static final Map<String, Map<String, Map<String, Object>>> dataCasesMap = new HashMap();

    public static void parseDataCases(Element element, Map<String, String> keyMap, List<String> dslFiles) {
        Map attributeMap = XMLUtils.getAttributeMap(element);
        Iterator iterator = element.elementIterator();
        Map defaultMap = null;
        Map orginCaseDataMap = null;
        Map caseDataMap = null;
        DSLParamParse dslParamParse = new DSLParamParse();
        while (iterator.hasNext()) {
            Element row = (Element) iterator.next();
            if ("default".equals(row.getName())) {
                defaultMap = getData(row);
            } else {
                orginCaseDataMap = getData(row);
                mergeMap(orginCaseDataMap, defaultMap, keyMap);

                Map dataCaseAttributeMap = XMLUtils.getAttributeMap(row);
                String id = (String) dataCaseAttributeMap.get("id");
                String executor = (String) attributeMap.get("executor");

                Map dslParamMap = dslParamParse.getParamMap(executor, dslParamParse.read(dslFiles));
                caseDataMap = processData(orginCaseDataMap, dslParamMap);

                Map caseMap = new HashMap();
                caseMap.put(id, caseDataMap);

                Map checkMap = (Map) dataCasesMap.get(executor);
                if (checkMap == null) {
                    dataCasesMap.put(executor, caseMap);
                } else {
                    checkMap.putAll(caseMap);
                    dataCasesMap.put(executor, checkMap);
                }
            }
        }
    }

    private static Map<String, List<Map<String, String>>> mergeMap(Map<String, List<Map<String, String>>> caseMap, Map<String, List<Map<String, String>>> defaultMap, Map<String, String> keyMap) {
        Iterator iterator = defaultMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String key = null;
            if (keyMap != null) {
                key = (String) keyMap.get(entry.getKey());
            }
            if (key == null) {
                mergeNoKeyList(caseMap, entry);
            } else {
                checkDuplicateKey(key, (List) entry.getValue());
                mergeKeyList(caseMap, entry, key);
            }
        }

        return caseMap;
    }

    private static void mergeNoKeyList(Map<String, List<Map<String, String>>> caseMap, Map.Entry<String, List<Map<String, String>>> entry) {
        List caseList = (List) caseMap.get(entry.getKey());
        if (caseList == null) {
            caseMap.put(entry.getKey(), entry.getValue());
        } else {
            List defaultList = (List) entry.getValue();
            caseMap.put(entry.getKey(), replaceList(caseList, defaultList));
        }
    }

    private static List replaceList(List caseList, List defaultList)
    {
        List newCaseList = new ArrayList();
        for(Iterator i$ = caseList.iterator(); i$.hasNext();)
        {
            Map cMap = (Map)i$.next();
            Iterator j$ = defaultList.iterator();
            while(j$.hasNext())
            {
                Map dMap = (Map)i$.next();
                Map newMap = copyMap(dMap);
                replaceMap(newMap, cMap);
                newCaseList.add(newMap);
            }
        }

        return newCaseList;
    }


    private static void replaceMap(Map newMap, Map cMap)
    {
        java.util.Map.Entry entry;
        for(Iterator iterator = cMap.entrySet().iterator(); iterator.hasNext(); newMap.put(entry.getKey(), entry.getValue()))
            entry = (java.util.Map.Entry)iterator.next();

    }

    private static void mergeKeyList(Map caseMap, java.util.Map.Entry entry, String key)
    {
        List caseList = (List)caseMap.get(entry.getKey());
        List newCaseList = new ArrayList();
        if(caseList == null)
        {
            caseMap.put(entry.getKey(), entry.getValue());
        } else
        {
            List defaultList = (List)entry.getValue();
            Iterator i$ = defaultList.iterator();
            do
            {
                if(!i$.hasNext())
                    break;
                Map dMap = (Map)i$.next();
                boolean equal = false;
                Iterator j$ = caseList.iterator();
                do
                {
                    if(!j$.hasNext())
                        break;
                    Map cMap = (Map)j$.next();
                    if(dMap.get(key) == null || !((String)dMap.get(key)).equalsIgnoreCase((String)cMap.get(key)))
                        continue;
                    Map tempMap = copyMap(dMap);
                    replaceMap(tempMap, cMap);
                    newCaseList.add(tempMap);
                    equal = true;
                    break;
                } while(true);
                if(!equal)
                    newCaseList.add(dMap);
            } while(true);
            newCaseList.addAll(getDiff(caseList, defaultList, key));
            caseMap.put(entry.getKey(), newCaseList);
        }
    }

    private static List<Map<String, String>> getDiff(List<Map<String, String>> caseMap, List<Map<String, String>> defaultMap, String key) {
        List diffList = new ArrayList();
        for (Map cMap : caseMap) {
            boolean equal = false;
            for (Map dMap : defaultMap) {
                if ((cMap.get(key) != null) && (((String) cMap.get(key)).equals(dMap.get(key)))) {
                    equal = true;
                    break;
                }
            }
            if (!equal)
                diffList.add(cMap);
        }
        return diffList;
    }

    private static void checkDuplicateKey(String key, List<Map<String, String>> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }
        List keyList = new ArrayList();
        for (Map aMap : dataList) {
            String value = (String) aMap.get(key);
            if (value != null) {
                if (keyList.contains(value)) {
                    throw new RuntimeException("存在相同的key:{}");
                }
                keyList.add(value);
            }
        }
    }

    private static Map<String, List<Map<String, String>>> getData(Element element) {
        Iterator iterator = element.elementIterator();
        Map dataCaseMap = new HashMap();
        while (iterator.hasNext()) {
            Element row = (Element) iterator.next();
            Map trMap = processRow(row);
            List listMap = (List) dataCaseMap.get(row.getName());
            if (CollectionUtils.isEmpty(listMap)) {
                listMap = new ArrayList();
            }
            listMap.add(trMap);
            dataCaseMap.put(row.getName(), listMap);
        }

        return dataCaseMap;
    }

    private static Map<String, Object> processData(Map<String, List<Map<String, String>>> dataCaseMap, Map<String, Set<String>> dslParamMap) {
        Map map = new HashMap();
        Iterator iterator = dataCaseMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            int count = entry.getValue() == null ? 0 : ((List) entry.getValue()).size();
            String name = (String) entry.getKey();
            map.putAll(parseList((String) entry.getKey(), (List) entry.getValue()));

            processOtherParam(map, count, name, (Set) dslParamMap.get(name));
        }

        return convertOneListToString(map);
    }

    private static Map<String, Object> convertOneListToString(Map<String, Object> map) {
        if (map == null) {
            return Collections.EMPTY_MAP;
        }
        Map newMap = new HashMap();
        Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            List list = (ArrayList) entry.getValue();
            if (list.size() == 1)
                newMap.put(entry.getKey(), list.get(0));
            else {
                newMap.put(entry.getKey(), entry.getValue());
            }
        }

        return newMap;
    }

    private static void processOtherParam(Map<String, Object> map, int count, String name, Set<String> dslParamSet) {
        if (dslParamSet == null) {
            return;
        }
        Iterator iterator = dslParamSet.iterator();
        while (iterator.hasNext()) {
            String param = (String) iterator.next();
            String key = name + "." + param;
            if (map.get(key) == null) {
                List valueList = generateValue(count);
                map.put(key, valueList);
            }
        }
    }

    private static List<String> generateValue(int count) {
        List valueList = new ArrayList();
        for (int i = 0; i < count; i++) {
            valueList.add("[null]");
        }
        return valueList;
    }

    private static Map<String, List<String>> parseList(String name, List<Map<String, String>> mapList) {
        Map map = new HashMap();
        if (CollectionUtils.isEmpty(mapList)) {
            return null;
        }
        for (int i = 0; i < mapList.size(); i++) {
            Map orginMap = (Map) mapList.get(i);
            parseMap(orginMap, map, i, name);
        }
        checkNumber(map, mapList.size());

        return map;
    }

    private static void checkNumber(Map map, int count)
    {
        java.util.Map.Entry entry;
        List valueList;
        for(Iterator iterator = map.entrySet().iterator(); iterator.hasNext(); map.put(entry.getKey(), valueList))
        {
            entry = (java.util.Map.Entry)iterator.next();
            valueList = (List)entry.getValue();
            if(valueList.size() != count)
                addList(valueList, count);
        }

    }

    private static void parseMap(Map<String, String> orginMap, Map<String, List<String>> map, int index, String name) {
        Iterator iterator = orginMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            String key = name + "." + (String) entry.getKey();
            List valueList = (List) map.get(key);
            if (valueList == null) {
                valueList = new ArrayList();
                addList(valueList, index);
            } else if (valueList.size() != index) {
                addList(valueList, index);
            }
            valueList.add(entry.getValue());
            map.put(key, valueList);
        }
    }

    private static void addList(List<String> valueList, int index) {
        while (index - valueList.size() > 0)
            valueList.add("[null]");
    }

    private static Map<String, String> processRow(Element trRow) {
        Map trMap = new HashMap();
        Iterator iterator = trRow.elementIterator();
        while (iterator.hasNext()) {
            Element element = (Element) iterator.next();
            trMap.put(element.getName(), element.getText());
        }
        trMap.putAll(XMLUtils.getAttributeMap(trRow));

        return trMap;
    }

    private static Map<String, String> copyMap(Map<String, String> srcMap) {
        Map destMap = new HashMap();
        if (srcMap == null) {
            return destMap;
        }
        Iterator iterator = srcMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            destMap.put(entry.getKey(), entry.getValue());
        }

        return destMap;
    }
}
